package com.esig.View;

import com.esig.Model.Bullet;
import com.esig.Model.PlayerOne;
import com.esig.Model.PlayerOther;
import com.esig.socket.ClientUI2;
import com.esig.socket.ServerUI2;
import com.esig.util.BulletsPool;

import javax.swing.*;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import static com.esig.util.Constant.*;

public class GameFrame extends JFrame implements Runnable {

    //定义双缓存图片 第一次使用的时候加载，而不是类加载的时候加载，
    private Image offScreemImage = null;
    //菜单指向 默认是0 即菜单页面，一开始绘制菜单页面，然后通过选择绘制不同的页面实现页面跳转
    private static int menuIndex = STATE_MENU;
    //指针图片默认y轴
    private static int selectY = SELECT_Y;
    //子弹(气功波)列表  可以加池
    public ArrayList<Bullet> bulletList = new ArrayList<Bullet>();
    //联机角色列表  可以加池
    public Map<Integer, PlayerOther> playerOtherList = new HashMap<Integer, PlayerOther>();
    //玩家一
    PlayerOne playerOne = new PlayerOne("src/main/resources/img/davis_0.png", this, "src/main/resources/img/davis_0.png", "src/main/resources/img/davis_1.png", "src/main/resources/img/davis_2.png", "src/main/resources/img/davis_0_mirror.png", "src/main/resources/img/davis_1_mirror.png", "src/main/resources/img/davis_2_mirror.png");
    //其他玩家
    //PlayerOther playerOther = new PlayerOther("src/main/resources/img/davis_0.png",  this, "src/main/resources/img/davis_0.png", "src/main/resources/img/davis_1.png", "src/main/resources/img/davis_2.png", "src/main/resources/img/davis_0_mirror.png", "src/main/resources/img/davis_1_mirror.png", "src/main/resources/img/davis_2_mirror.png");
    //客户端玩家输入的 连接的ip
    public static String ip = null;
    //获取客户端类，目的是通过按键发送消息
    public static ClientUI2 ui;


    public GameFrame() {
        initFrame();
        //键盘监听
        addKeyListener(new GameFrame.CustomKeyListener());
        //重绘
        new Thread(this).start();
    }

    /**
     * 属性进行初始化
     */
    private void initFrame() {
        //设置游戏标题
        setTitle(GAME_TITLE);
        //设置窗口大小
        setSize(FRAME_WIDTH, FRAME_HEIGHT);
        //窗口居中
        setLocationRelativeTo(null);
        //设置窗口大小不可改变
        setResizable(false);
        //3 直接关闭应用程序 0是不执行任何操作，1是只隐藏解密，2是隐藏并释放窗体
        setDefaultCloseOperation(3);
        //设置窗口可见
        setVisible(true);
    }

    /**
     * 绘制菜单等
     *
     * @param g
     */
    @Override
    public void paint(Graphics g) {
        //创建和容器一样大小的Image图片
        if (offScreemImage == null) {
            offScreemImage = this.createImage(FRAME_WIDTH, FRAME_HEIGHT);
        }
        //获得该图片的画笔
        Graphics gImage = offScreemImage.getGraphics();

        //设置画笔颜色
        gImage.setColor(GAME_BACKGROUND_COLOR);
        //绘制实心矩形  填充
        gImage.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
        //改变画笔颜色
        gImage.setColor(GAME_COLOR);
        //改变文字大小和样式
        gImage.setFont(GAME_FONT);

        /**
         * 根据menuIndex 去 重绘页面，其实就是执行下面的方法去执行页面跳转
         */
        switch (menuIndex) {
            case STATE_MENU:        //菜单
                drawMenu(gImage);
                break;
            case STATE_ONE:         //单人模式
                drawOne(gImage);
                break;
            case ONLINE_MENU:       //选择开启联机，还是等待联机
                drawOnlineMenu(gImage);
                break;
            case STATE_ONLINE:       //服务器端开启联机
                drawOnline(gImage);
                break;
            case JOIN_ONLINE:        //填写ip地址
                drawJoinOnline(gImage);
                break;
            case JOIN_ONLINE_SUCCESS://客户端联机成功页面
                drawJoinOnlineSuccess(gImage, ip);
                break;
            case STATE_HELP:         //帮助界面
                drawHelp(gImage);
                break;
            case STATE_OVER:        //退出
                drawOver(gImage);
                break;
        }


        /** 将缓存区绘制好的图形整个绘制到容器的画布中 */
        g.drawImage(offScreemImage, 0, 0, null);
    }

    /**
     * 一个个重绘的方法，一个个界面
     *
     * @param gImage
     */

    //绘制菜单
    private void drawMenu(Graphics gImage) {
        //添加文字  从常量里面获取菜单选项
        for (int i = 0; i < MENUS.length; i++) {
            FontMetrics metrics = gImage.getFontMetrics(GAME_FONT);  //设置字体样式 获取metrics 为了后续获取宽度
            int x = (FRAME_WIDTH - metrics.stringWidth(MENUS[i])) / 2;  //计算居中的x值
            gImage.drawString(MENUS[i], x, 200 + i * 50);
            //这里加个for循环好一点？
            if (selectY == 165 && i == MENUS.length - 1) {
                int x1 = (FRAME_WIDTH - metrics.stringWidth(MENUS[0])) / 2;  //计算居中的x值
                gImage.setColor(GAME_TITTLE_FONT_COLOR);
                gImage.drawString(MENUS[0], x1, 200 + 0 * 50);
                gImage.setColor(GAME_COLOR);

            } else if (selectY == 215 && i == MENUS.length - 1) {
                int x1 = (FRAME_WIDTH - metrics.stringWidth(MENUS[1])) / 2;  //计算居中的x值

                gImage.setColor(GAME_TITTLE_FONT_COLOR);
                gImage.drawString(MENUS[1], x1, 200 + 1 * 50);
                gImage.setColor(GAME_COLOR);

            } else if (selectY == 265 && i == MENUS.length - 1) {
                int x1 = (FRAME_WIDTH - metrics.stringWidth(MENUS[2])) / 2;  //计算居中的x值

                gImage.setColor(GAME_TITTLE_FONT_COLOR);
                gImage.drawString(MENUS[2], x1, 200 + 2 * 50);
                gImage.setColor(GAME_COLOR);

            } else if (selectY == 315 && i == MENUS.length - 1) {
                int x1 = (FRAME_WIDTH - metrics.stringWidth(MENUS[3])) / 2;  //计算居中的x值
                gImage.setColor(GAME_TITTLE_FONT_COLOR);
                gImage.drawString(MENUS[3], x1, 200 + 3 * 50);
                gImage.setColor(GAME_COLOR);

            }
        }

        //绘制标题
        FontMetrics metrics = gImage.getFontMetrics(GAME_TITTLE_FONT);  //设置字体样式
        int x = (FRAME_WIDTH - metrics.stringWidth("Litter fighter 2")) / 2;  //计算居中的x值
        gImage.setFont(GAME_TITTLE_FONT);
        gImage.setColor(GAME_TITTLE_FONT_COLOR);
        gImage.drawString("Litter fighter 2", x, 100);
        //绘制副标题
        gImage.setFont(GAME_SECOND_TITTLE_FONT);
        gImage.drawString("小朋友齐打交(二) ver 2.0a", 550, 130);
        //绘制背景图
        gImage.drawImage(GAME_MENU_BACKGROUND, 300, 350, null);
        //绘制图片指针
        gImage.drawImage(GAME_SELECT, 200, selectY, null);

//        gImage.drawImage(playerOne.img, 100,200,GAME_COLOR,null);
    }

    //选择单机游戏的绘图
    private void drawOne(Graphics gImage) {
        //背景图片绘制
        gImage.drawImage(GAME_BACKGROUND, 0, 0, 900, 700, null);
        //绘制玩家一
        playerOne.paintSelf(gImage);
        //绘制气功波 循环子弹列表，并绘制，主要是因为每30ms重绘
        for (Bullet bullet : bulletList) {
            bullet.paintSelf(gImage);
        }
    }

    //选择创建联机游戏的绘图
    public boolean rePaintOnline = true; //只执行一次的绘画判定
    int rePaintOnlineI = 0;   //确保先执行了绘图，因为连接socket会阻塞

    private void drawOnline(Graphics gImage) {
        rePaintOnlineI++;
        FontMetrics metrics = gImage.getFontMetrics(GAME_FONT);  //设置字体样式
        int x = (FRAME_WIDTH - metrics.stringWidth("联机房间创建完毕,请重新打开，并输入您的ip地址进入对局")) / 2;  //计算居中的x值
        gImage.drawString("联机房间创建完毕,请重新打开，并输入您的ip地址进入对局", x, 300);
        int x1 = (FRAME_WIDTH - metrics.stringWidth("并确保当前窗口不关闭")) / 2;  //计算居中的x值

        gImage.drawString("并确保当前窗口不关闭", x1, 350);
//        GameMain.main(null);

        if (rePaintOnline && rePaintOnlineI > 1) {
            rePaintOnline = false;
            ServerUI2.main(null);
            //下面是进程测试，失败了
//            try {
////                Runtime.getRuntime().exec(".\\1.txt");
//                Process pr = Runtime.getRuntime().exec("java ServerUI2.java");
//                int exitValue =  pr.waitFor();
//                System.out.println(exitValue);
//                System.out.println(Runtime.getRuntime().freeMemory());
//                System.out.println(Runtime.getRuntime().totalMemory());
//                System.out.println(Runtime.getRuntime().maxMemory());
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//            System.out.println(this);
        }

    }

    //选择联机游戏的绘图
    private void drawOnlineMenu(Graphics gImage) {
        try {
            //标题
            FontMetrics metrics = gImage.getFontMetrics(GAME_TITTLE_FONT);  //设置字体样式
            int x = (FRAME_WIDTH - metrics.stringWidth("Litter fighter 2")) / 2;  //计算居中的x值
            gImage.setFont(GAME_TITTLE_FONT);
            gImage.setColor(GAME_TITTLE_FONT_COLOR);
            gImage.drawString("Litter fighter 2", x, 200);
            //绘制副标题
            gImage.setFont(GAME_SECOND_TITTLE_FONT);
            gImage.drawString("小朋友齐打交(二) ver 2.0a", 550, 230);

            //两个背景图
            gImage.drawImage(ONLINE_MENU_BACKGROUND_ONE, 100, 350, null);
            gImage.drawImage(ONLINE_MENU_BACKGROUND_TWO, 700, 350, null);

            //内容
            FontMetrics metrics2 = gImage.getFontMetrics(GAME_FONT);  //设置字体样式 获取metrics 为了后续获取宽度
            int width = metrics2.stringWidth("你的IP地址为：" + InetAddress.getLocalHost().getHostAddress());
            int x2 = (FRAME_WIDTH - width) / 2;  //计算居中的x值
            gImage.setFont(GAME_FONT);
            gImage.setColor(Color.black);
            //绘制矩形
            gImage.fillRect(x2, 270, width, 40);
            gImage.setColor(Color.GRAY);

            gImage.drawString("你的IP地址为：" + InetAddress.getLocalHost().getHostAddress(), x2, 300);
            gImage.setColor(GAME_COLOR);
            gImage.drawRect(x2, 325, width, 200);
        } catch (UnknownHostException e) {
            System.out.println(e);
        }

        gImage.drawString("等待好友加入", 400, 400);
        gImage.drawString("加入好友的房间", 400, 475);
        //绘制图片指针
        gImage.drawImage(GAME_SELECT, 300, selectY, null);
    }

    //选择加入联机时的绘图
    public boolean rePaintJoin = true; //只执行一次的绘画判定

    private void drawJoinOnline(Graphics gImage) {
        if (rePaintJoin) {
            rePaintJoin = false;
            ip = JOptionPane.showInputDialog("输入链接的IP地址：");
        }
        //ip不等于null，时进入客户端联机页面
        if (ip != null) {
            menuIndex = JOIN_ONLINE_SUCCESS;
        } else {
            menuIndex = ONLINE_MENU;
            rePaintJoin = true; //让他可以再执行一次
        }
    }

    //输入完联机ip时的绘图
    public boolean rePaintOnlineSuccess = true; //只执行一次的绘画判定


    private void drawJoinOnlineSuccess(final Graphics gImage, String ip) {
        if (rePaintOnlineSuccess) {
            rePaintOnlineSuccess = false;
            System.out.println("输入完联机ip时的绘图,ip:" + ip);
            ui = new ClientUI2(ip, this);
        }

        //背景图片绘制
        gImage.drawImage(GAME_BACKGROUND, 0, 0, 900, 700, null);
        gImage.setColor(Color.BLACK);
        gImage.drawString("加入好友的房间成功，ip:" + ip, 30, 680);
        //绘制所有联机玩家
        for (PlayerOther playerOther : playerOtherList.values()) {
            playerOther.paintSelf(gImage);
        }

        //绘制气功波 循环子弹列表，并绘制，主要是因为每30ms重绘
        for (Bullet bullet : bulletList) {
            bullet.paintSelf(gImage);
        }
        //是遍历所有的子弹，将不可见的子弹移除，并还原回对象池
        for (int i = 0; i < bulletList.size(); i++) {
            Bullet bullet = bulletList.get(i);
            if (!(bullet.getVisible())) {
                Bullet remove = bulletList.remove(i);
                i--;
                BulletsPool.theReturn(remove);
            }
        }
    }

    PlayerOther player1 = new PlayerOther("src/main/resources/img/davis_0.png", 50, 150, 130, 230, this, "src/main/resources/img/davis_0.png", "src/main/resources/img/davis_1.png", "src/main/resources/img/davis_2.png", "src/main/resources/img/davis_0_mirror.png", "src/main/resources/img/davis_1_mirror.png", "src/main/resources/img/davis_2_mirror.png");
    PlayerOther player2 = new PlayerOther("src/main/resources/img/davis_0.png", 50, 250, 130, 330, this, "src/main/resources/img/davis_0.png", "src/main/resources/img/davis_1.png", "src/main/resources/img/davis_2.png", "src/main/resources/img/davis_0_mirror.png", "src/main/resources/img/davis_1_mirror.png", "src/main/resources/img/davis_2_mirror.png");
    PlayerOther player3 = new PlayerOther("src/main/resources/img/davis_0.png", 50, 400, 130, 480, this, "src/main/resources/img/davis_0.png", "src/main/resources/img/davis_1.png", "src/main/resources/img/davis_2.png", "src/main/resources/img/davis_0_mirror.png", "src/main/resources/img/davis_1_mirror.png", "src/main/resources/img/davis_2_mirror.png");
    PlayerOther player4 = new PlayerOther("src/main/resources/img/davis_0.png", 50, 500, 130, 580, this, "src/main/resources/img/davis_0.png", "src/main/resources/img/davis_1.png", "src/main/resources/img/davis_2.png", "src/main/resources/img/davis_0_mirror.png", "src/main/resources/img/davis_1_mirror.png", "src/main/resources/img/davis_2_mirror.png");
    PlayerOther player5 = new PlayerOther("src/main/resources/img/davis_0.png", 50, 600, 130, 680, this, "src/main/resources/img/davis_0.png", "src/main/resources/img/davis_1.png", "src/main/resources/img/davis_2.png", "src/main/resources/img/davis_0_mirror.png", "src/main/resources/img/davis_1_mirror.png", "src/main/resources/img/davis_2_mirror.png");

    //选择帮助界面时的绘图
    private void drawHelp(Graphics gImage) {
        //TODO
        //玩法介绍
        gImage.drawString("玩法介绍", 100, 100);
        gImage.drawString("如何进入游戏", 600, 100);


        player1.paintSelfHelp(gImage);
        player1.keyPD();
        if(player1.dx2 > 130) {
            player1.dx1 = 50;
            player1.dx2 = 130;
        }
        gImage.setColor(Color.white);
        gImage.setFont(GAME_SECOND_TITTLE_FONT);
        gImage.drawRect(222,185,20,20);
        gImage.drawString("w",230,200);

        gImage.drawRect(222,215,20,20);
        gImage.drawString("s",230,230);

        gImage.drawRect(192,215,20,20);
        gImage.drawString("a",200,230);

        gImage.drawRect(252,215,20,20);
        gImage.drawString("d",260,230);


        player2.paintSelfHelp(gImage);
        player2.keyJ();
        if(player2.dx2 > 130) {
            player2.dx1 = 50;
            player2.dx2 = 130;
        }
        gImage.drawRect(222,285,20,20);
        gImage.drawString("j",230,300);

        player3.paintSelfHelp(gImage);
        player3.jump();
        gImage.drawRect(222,385,20,20);
        gImage.drawString("k",230,400);

        player4.paintSelfHelp(gImage);
        player4.killOneOne();
        if(player4.dx2 > 130) {
            player4.dx1 = 50;
            player4.dx2 = 130;
        }
        gImage.drawRect(222,485,20,20);
        gImage.drawString("u",230,500);

        player5.paintSelfHelp(gImage);
        player5.keyI();
        gImage.drawRect(222,635,20,20);
        gImage.drawString("i",230,650);

        //进入游戏帮助
        gImage.drawString("1.这个游戏制作的初衷是学习JavaSE，然后是想试着做一",500,200);
        gImage.drawString("个可以和朋友愉快开黑的游戏，想到了小时候玩的lf2!",500,250);
        gImage.drawString("虽然现在还有很多不足，但是我已经十分满意了！",500,300);
        gImage.drawString("2.玩家点击联机模式，然后需要一个玩家开房间，点击等",500,350);
        gImage.drawString("待好友加入,然后你的小伙伴通过你的ip地址就可以和你",500,400);
        gImage.drawString("联机了，当然你也要重新启动程序，进入房间",500,450);
        gImage.drawString("3.菜单界面时，ws或者上下选择模式，回车确定，",500,500);
        gImage.drawString("esc回到首菜单页面",500,550);





    }

    //退出
    private void drawOver(Graphics gImage) {
        System.exit(0);
    }


    /**
     * 键盘监视器
     */
    class CustomKeyListener implements KeyListener {
        public void keyTyped(KeyEvent e) {
        }

        /**
         * 键盘按下事件
         * 不同的游戏状态，给出不同的键盘处理的方法。
         * 其中退出是不需要键盘处理的，游戏直接关了
         *
         * @param e
         */
        public void keyPressed(KeyEvent e) {
            //获得被按下键的键值
            int keyCode = e.getKeyCode();

            switch (menuIndex) {
                case STATE_MENU:
                    keyPressedEventMenu(keyCode);
                    break;
                case STATE_ONE:
                    keyPressedEventOne(keyCode);
                    break;
                case ONLINE_MENU:
                    keyPressedEventOnlineMenu(keyCode);
                    break;
                case JOIN_ONLINE_SUCCESS:
                    keyPressedEventOnlineSuccess(keyCode);
                    break;
                case STATE_HELP:
                    keyPressedEventHelp(keyCode);
                    break;

            }

        }

        /**
         * 菜单栏的按下按键操作
         */
        private void keyPressedEventMenu(int keyCode) {
            /**
             * 根据上下键盘更改指针图标的位置
             */
            switch (keyCode) {
                case KeyEvent.VK_UP:
                case KeyEvent.VK_W:
                    selectY = selectY - 50;
                    if (selectY < 165) {
                        selectY = 315;
                    }
                    break;
                case KeyEvent.VK_DOWN:
                case KeyEvent.VK_S:
                    selectY = selectY + 50;
                    if (selectY > 315) {
                        selectY = 165;
                    }
                    break;
                /**
                 * 根据上面的selectY去执行
                 * 回车事件重绘，回调上面的drawXxx
                 */
                case KeyEvent.VK_ENTER:
                    switch (selectY) {
                        case 165:
                            menuIndex = STATE_ONE;
                            break;
                        case 215:
                            menuIndex = ONLINE_MENU;
                            selectY = 365; //调整指针位置
                            break;
                        case 265:
                            menuIndex = STATE_HELP;
                            break;
                        case 315:
                            menuIndex = STATE_OVER;
                            break;
                    }
            }
        }

        /**
         * 单人模式的按下按键操作
         */
        private void keyPressedEventOne(int keyCode) {
            playerOne.keyPressed(keyCode);
            if (keyCode == KeyEvent.VK_ESCAPE) menuIndex = STATE_MENU; //默认情况下esc 回到首页

        }

        /**
         * 联机模式菜单选择的按下按键操作
         */
        private void keyPressedEventOnlineMenu(int keyCode) {
            /**
             * 根据上下键盘更改指针图标的位置
             */
            switch (keyCode) {
                case KeyEvent.VK_UP:
                case KeyEvent.VK_W:
                    selectY = selectY - 75;
                    if (selectY != 365) {
                        selectY = 440;
                    }
                    break;
                case KeyEvent.VK_DOWN:
                case KeyEvent.VK_S:
                    selectY = selectY + 75;
                    if (selectY != 440) {
                        selectY = 365;
                    }
                    break;

                /**
                 * 根据上面的selectY去执行
                 * 回车事件重绘，回调上面的drawXxx
                 */
                case KeyEvent.VK_ENTER:
                    switch (selectY) {
                        case 365:
                            menuIndex = STATE_ONLINE;
                            break;
                        case 440:
                            menuIndex = JOIN_ONLINE;
                            break;
                    }
                    break;
                case KeyEvent.VK_ESCAPE:
                    selectY = 165;
                    menuIndex = STATE_MENU; //默认情况下esc 回到首页
                    break;
            }
        }

        /**
         * 联机模式的按下按键操作
         */
        private void keyPressedEventOnlineSuccess(int keyCode) {
            //TODO
            ui.OnlineKeyPressed(keyCode);
            if (keyCode == KeyEvent.VK_ESCAPE) menuIndex = STATE_MENU; //默认情况下esc 回到首页 不太好

        }

        /**
         * 帮助模式的按下按键操作
         */
        private void keyPressedEventHelp(int keyCode) {
            if (keyCode == KeyEvent.VK_ESCAPE) menuIndex = STATE_MENU; //默认情况下esc 回到首页
        }


        /**
         * 键盘松开事件
         *
         * @param e
         */
        public void keyReleased(KeyEvent e) {
            //获得被松开键的键值
            int keyCode = e.getKeyCode();

            switch (menuIndex) {
                case STATE_ONE:
                    keyReleasedEventOne(keyCode);
                    break;
                case JOIN_ONLINE_SUCCESS:
                    keyReleasedEventOnline(keyCode);
                    break;
            }
        }

        /**
         * 单人模式的松开按键操作
         */
        private void keyReleasedEventOne(int keyCode) {
            playerOne.keyReleased(keyCode);
        }
    }

    /**
     * 联机模式的松开按键操作
     */
    private void keyReleasedEventOnline(int keyCode) {
        //TODO
        ui.OnlineKeyReleased(keyCode);
    }


    /**
     * 重绘
     */
    public void run() {
        while (true) {
            repaint();
            try {
                Thread.sleep(REPAINT_INTERVAL);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
